"""This file is part of uio-to-graphviz.

uio-to-graphviz is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

uio-to-graphviz is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with uio-to-graphviz. If not, see <http://www.gnu.org/licenses/>.
"""

# This file provides a convinient mapping between a course code and the actuall website.
# This information is stored in UiOUrl class which has the ability to go between these two.
# If given a course code it will look it up in the 'course' dictionary, which is created by
# visiting each faculties webpage.
from HTMLParser import HTMLParser
from urllib import urlopen
import pickle
import re

class UiOUrl:
    def __init__(self, url):
        self.parser = CourseParser()
        
        if url.startswith('http://'):   # if webpage do nothing
            self.url = url
        else:                           # else find webpage
            self.url = self.lookup(url)

    def __call__(self):
        return self.url

    def __str__(self):
        return "%s: %s" % (self.courseCode(), self())
    
    def courseCode(self):
        # given full url
        # 'http://www.uio.no/studier/emner/hf/iln/NORINT0142/'
        # returns
        # 'NORINT0142'
        s = self.url.split('/')
        if s[-1] == '' or s[-1].endswith('.xml'):
            return s[-2]
        else:
            return s[-1]
        
    def lookup(self, urlStriped):
        # Try to lookup course code, if it fails 'courses' will be recreated
        # throws KeyError on failure.
        try:
            return courses[urlStriped]
        except KeyError:
            print urlStriped, 'not found, recreating course list'
            self.recreateCourses()
            return courses[urlStriped]  # if it fails now we throw an error

    def recreateCourses(self):
        # recreate the 'courses' dictionary by visiting each faculty.
        url_stem = "http://www.uio.no/studier/emner/"
        faculties = ["hf", "jus", "matnat", "odont", "sv", "uv", "annet", "medisin", "teologi"]
        for i in range(len(faculties)):
            website = url_stem + faculties[i] + "/"

            s = self.read(website)
            for xmlSite in re.findall(r'&nbsp;<a href="(.*)\.xml', s): # hf has divided its page into multiple subpages.
                s += self.read(website + xmlSite + '.xml')
            self.parser.feed(s)
        self.parser.close()

        # courses has been updated, write new version to file
        f = open('uioUrl.pickle', 'w')
        pickle.dump(courses, f)
        f.close()

    def read(self, website):
        # todo: merge with read function in uioCoursesGraphviz.py
        print 'Visiting', website
        page = urlopen(website)
        encoding = page.headers.getparam('charset')
        if encoding != None:
            s = page.read().decode(encoding)
            page.close()                
        else:
            raise LookupError('Could not read %s' % website)
        return s

# either load from file or create an empty dictionary
try:
    f = open('uioUrl.pickle', 'r')
    courses = pickle.load(f)
    f.close()
except (IOError, EOFError):
    courses = dict()

class CourseParser(HTMLParser):
    # Fills up the dictionary 'courses' with entries like this:
    # {'NORINT0142': http://www.uio.no/studier/emner/hf/iln/NORINT0142/}
    def __init__(self):
        self.found = False
        HTMLParser.__init__(self)

    def handle_starttag(self, tag, attr):
        if len(attr) != 0:
            if tag == 'ul':
                if attr[0][1] == 'main':
                    self.found = True
            elif self.found:
                if tag == 'a' and attr[0][0] == 'href':
                    if attr[0][1].startswith('http://'):
                        u = UiOUrl(attr[0][1])
                        courses[u.courseCode()] = u()
                    elif attr[0][1].startswith('/studier/emner/'): # some references has the first part missing
                        u = UiOUrl('http://www.uio.no/' + attr[0][1])
                        courses[u.courseCode()] = u()
            
    def handle_endtag(self, tag):
        if tag == 'ul' and self.found == True:
            self.found = False

if __name__ == '__main__':
    # TESTS:
    print UiOUrl('CONT4101')
    print UiOUrl('MAT1120')
    print UiOUrl('ERN1000')
    print UiOUrl('ANT1100')
    print UiOUrl('GERM1101')
